/*
 * by: chenming
 * date: 2023/5/12
 * desc: 生成流程
 *
 * */

import {
  BPMNModdleOBJ,
  ElementExtend,
} from '@/views/project-setting/process/process';
import BpmnModdle, { ElementTypes } from 'bpmn-moddle';
import md5 from 'js-md5';
// import processModel from '@/views/project-setting/process/common/process-model';
import FlowablePackages from './flowable.json';

// 根据节点生成 userTask 和 多实例任务的 variable
const genUserTasks = (
  moddler: BPMNModdleOBJ,
  nodes: { name: string; userNameStr: string }[]
): any => {
  let userTasks: ElementTypes['bpmn:UserTask'][] = [];
  const variable: any = {};
  const userTaskIds: string[] = [];
  if (nodes.length) {
    // 创建流程发起节点
    const startUserTask = moddler.create('bpmn:UserTask', {
      'id': 'UserTask_0',
      'name': '流程发起',
      // eslint-disable-next-line no-template-curly-in-string
      'flowable:assignee': '${submiter}',
    });
    userTasks = nodes.map(
      (
        node: { name: string; userNameStr: string },
        index: number
      ): ElementTypes['bpmn:UserTask'] => {
        const flag: string = md5(`${new Date().getTime()}_${index}`);
        const userTaskId = `UserTask_${flag}`;
        const userTask: ElementTypes['bpmn:UserTask'] = moddler.create(
          'bpmn:UserTask',
          {
            'id': userTaskId,
            'name': node.name || `节点_${userTaskId}`,
            'flowable:assignee': `\${${userTaskId}}`,
          }
        );

        // 创建多实例任务 bpmn:MultiInstanceLoopCharacteristics
        const userNames: string[] = node.userNameStr
          ? node.userNameStr?.split(',')
          : [];
        if (userNames.length) {
          variable[userTaskId] = node.userNameStr;
          userTaskIds.push(userTaskId);
          const loopCharacteristics: ElementTypes['bpmn:MultiInstanceLoopCharacteristics'] =
            moddler.create('bpmn:MultiInstanceLoopCharacteristics', {
              'flowable:assigneeType': 'person',
              'flowable:collection': `\${multiService.getCollection(${userTaskId})}`,
              'flowable:elementVariable': userTaskId,
            });
          // 完成条件
          // eslint-disable-next-line no-template-curly-in-string
          const completionCondition: ElementTypes['bpmn:FormalExpression'] =
            moddler.create('bpmn:FormalExpression', {
              // eslint-disable-next-line no-template-curly-in-string
              'body': '${ nrOfCompletedInstances == nrOfInstances }',
              'xsi:type': 'bpmn:tFormalExpression',
            });
          completionCondition.$parent = loopCharacteristics;
          // loopCharacteristics.set('completionCondition', completionCondition);
          loopCharacteristics.completionCondition = completionCondition;
          loopCharacteristics.$parent = userTask;
          // userTask.set('loopCharacteristics', loopCharacteristics);
          // 把多实例任务 MultiInstanceLoopCharacteristics 挂载到userTask
          userTask.loopCharacteristics = loopCharacteristics;
        }
        return userTask;
      }
    );
    userTasks.unshift(startUserTask);
  }

  return { userTasks, variable, userTaskIds };
};

// 生成 process 的 flowElements;
const genFlowElements = (
  moddler: any,
  UserTasks: ElementTypes['bpmn:UserTask'][]
): any[] => {
  const flowElements: any[] = [];
  let bpmnElements: any[];
  const bpmnStartEvent = moddler.create('bpmn:StartEvent', {
    id: 'StartEvent_0',
  });
  const bpmnEndEvent = moddler.create('bpmn:EndEvent', {
    id: 'EndEvent_0',
  });
  // eslint-disable-next-line prefer-const
  bpmnElements = [bpmnStartEvent, ...UserTasks, bpmnEndEvent];
  const len = bpmnElements.length;
  for (let i = 0; i < len; i++) {
    const el = bpmnElements[i];
    if (i - 2 >= 0) {
      const sourceRef = bpmnElements[i - 2];
      const targetRef = bpmnElements[i - 1];
      const SequenceFlowId = `bpmnSequenceFlow_${md5(
        `${new Date().getTime()}_${i}`
      )}`;
      const bpmnSequenceFlow = moddler.create('bpmn:SequenceFlow', {
        id: SequenceFlowId,
        sourceRef,
        targetRef,
      });
      sourceRef.set('outgoing', [bpmnSequenceFlow]);
      targetRef.set('incoming', [bpmnSequenceFlow]);
      flowElements.push(bpmnSequenceFlow);
    }
    flowElements.push(el);

    if (i === len - 1) {
      const sourceRef = bpmnElements[i - 1];
      const targetRef = bpmnElements[i];
      const SequenceFlowId = `bpmnSequenceFlow_${md5(
        `${new Date().getTime()}_${i}_end`
      )}`;
      const bpmnSequenceFlow = moddler.create('bpmn:SequenceFlow', {
        id: SequenceFlowId,
        sourceRef,
        targetRef,
      });
      sourceRef.set('outgoing', [bpmnSequenceFlow]);
      targetRef.set('incoming', [bpmnSequenceFlow]);
      flowElements.push(bpmnSequenceFlow);
    }
  }
  return flowElements;
};
// eslint-disable-next-line consistent-return
export const genXMLByNodes = async (
  nodes: any[],
  processConfig: { name: string }
  // eslint-disable-next-line consistent-return
): Promise<any> => {
  if (nodes) {
    const moddler: BPMNModdleOBJ = new BpmnModdle({
      flowable: FlowablePackages,
    }) as BPMNModdleOBJ;
    // console.log('moddler: ', moddler);
    // const def = await moddler.fromXML(processModel);
    // console.log('def: ', def);
    // 创建根节点 bpmn:Definitions
    const bpmnRoot: ElementExtend = moddler.create('bpmn:Definitions', {
      'xmlns': 'http://www.omg.org/spec/BPMN/20100524/MODEL',
      'xmlns:bpmndi': 'http://www.omg.org/spec/BPMN/20100524/DI',
      'xmlns:flowable': 'http://flowable.org/bpmn',
      'xmlns:omgdc': 'http://www.omg.org/spec/DD/20100524/DC',
      'xmlns:omgdi': 'http://www.omg.org/spec/DD/20100524/DI',
      'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
      'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
      'targetNamespace': 'http://www.flowable.org/processdef',
    }) as unknown as ElementExtend;
    // console.log('bpmnRoot: ', bpmnRoot);
    // 创建事件监听 flowable:EventListener
    const eventListener = moddler.create('flowable:EventListener', {
      // eslint-disable-next-line no-template-curly-in-string
      delegateExpression: '${eventListener}',
      events: 'TASK_CREATED,TASK_COMPLETED',
    });
    const extensionElement = moddler.create('bpmn:ExtensionElements', {
      values: [eventListener],
    });
    // 创建 process
    const processId = `MyProcess_${md5(`${new Date().getTime()}_1`)}`;
    const bpmnProcess: ElementExtend = moddler.create('bpmn:Process', {
      id: processId,
      isExecutable: true,
      name: processConfig.name ? processConfig.name : `流程_${processId}`,
      extensionElements: extensionElement,
    }) as unknown as ElementExtend;
    extensionElement.$parent = bpmnProcess;
    // 生成多个任务节点 userTasks
    const { userTasks, variable, userTaskIds } = genUserTasks(moddler, nodes);
    // 生成process内的全部flowElements， 包含 startEvent, userTask, sequenceFlow, endEvent
    const flowElements = genFlowElements(moddler, userTasks);
    // 把flowElements挂载到process
    if (flowElements.length) {
      flowElements.forEach((el) => {
        el.$parent = bpmnProcess;
        bpmnProcess.get('flowElements').push(el);
      });
    }
    bpmnProcess.$parent = bpmnRoot;
    // 把process挂载到根节点bpmn:Definitions
    bpmnRoot.get('rootElements').push(bpmnProcess);
    // 根据 根节点 生成 xml
    const result = await moddler.toXML(bpmnRoot);
    // console.log('result:', result);
    // const obg = await moddler.fromXML(result.xml);
    // console.log('obg: ', obg);
    return new Promise((resolve, reject) => {
      if (result.xml) {
        resolve({
          xml: result.xml,
          variable,
          processConfig: {
            processId,
            name: bpmnProcess.get('name') || '',
          },
          userTaskIds,
        });
      } else {
        reject(new Error('process error!'));
      }
    });
  }
  // eslint-disable-next-line prefer-promise-reject-errors
  return Promise.reject('no nodes!');
};

export default null;
